﻿#pragma once
#include "PhysicsManager.h"
#include "PhysShape.h"
#include "AngelScriptBinder.h"

_NAMESPACE_BEGIN

/// Shape组，在PhysX中区分不同性质的Shape，比如controller的碰撞
enum ShapeGroup
{
	Shape_Group_Default=0,
	Shape_Group_Terrain ,
	Shape_Group_Pushable,
	Shape_Group_Particle,
	Shape_Group_Nonpushable = 10
};

/// Actor组，在PhysX中区分不同性质的Actor
enum ActorGroup
{
	Actor_Group_Default=0,
	Actor_Group_Terrain,
	Actor_Group_Plane
};

class PhysXObj;
//////////////////////////////////////////////////////////////////////////

/// 基本物理形状
class PhysXPrimitive
{
public:
	PhysXPrimitive();
	virtual ~PhysXPrimitive();

	/// 设置PhysX的Shape指针
	virtual void SetShapePtr(NxShape* p);

	/// 设置Ogre的渲染节点
	virtual void SetRenderNode(SceneNode* node){renderNode = node;}

	/// 获取渲染节点
	virtual SceneNode* GetRenderNode(){return renderNode;}

	/// 设置上级归属
	virtual void SetOwner(PhysXObj* p){this->pOwner=p;}

	///	获取上级归属指针
	PhysXObj* GetOwner(){return pOwner;}

	/// 设置本地的朝向矩阵
	NxMat34 GetLocalPose(){return pshape->getLocalPose();}
	
	/// 获取AABB
	virtual NxVec3 GetAABB(){assert("没有重写GetAABB方法");return NxVec3(0,0,0);}

	SceneNode* GetRenderNode()const{return renderNode;}
	NxShape* pshape;

protected:
	PhysXObj* pOwner;
	SceneNode *renderNode;	// 一个shape对应一个node，连接图形和物理
};

//////////////////////////////////////////////////////////////////////////

/// 物理立方体

class CubeShape:public PhysXPrimitive
{
public:		

	/// 创建物理立方体，由别处调用
	void Create(const Cube_Desc& desc,NxActorDesc& actorDesc,NxActor* pActor);

	/// 设置尺寸
	void SetSize(float x,float y,float z);

	/// 获取尺寸
	NxVec3 GetSize();

	/// 设置Shape指针
	void SetShapePtr(NxShape* p);

	/// 重写的获取AABB方法
	NxVec3 GetAABB(){return *(NxVec3*)&GetSize();}

	///
	typedef Cube_Desc DescType;

protected:
	NxBoxShapeDesc boxDesc;

private:
};

//////////////////////////////////////////////////////////////////////////
//球体
class SphereShape:public PhysXPrimitive
{
public:
	SphereShape(){}
	void Create(const Sphere_Desc& desc,NxActorDesc& actorDesc,NxActor* pActor);
	void SetRadius(float radius);
	float GetRadius();
	void SetShapePtr(NxShape* p);
	NxVec3 GetAABB(){return NxVec3(GetRadius()*2,GetRadius()*2,GetRadius()*2);}
	typedef Sphere_Desc DescType;
protected:
	NxSphereShapeDesc sphereDesc;

private:
};

//////////////////////////////////////////////////////////////////////////
//胶囊
class CapsuleShape:public PhysXPrimitive
{
public:
	void Create(const Capsule_Desc& desc,NxActorDesc& actorDesc,NxActor* pActor);
	void SetParam(float radius,float height);

	float GetHeight();
	float GetRadius();
	void SetShapePtr(NxShape* p);
	NxVec3 GetAABB(){return NxVec3(GetRadius()*2,GetHeight()+GetRadius()*2,GetRadius()*2);}

	typedef Capsule_Desc DescType;
protected:
	NxCapsuleShapeDesc capsuleDesc;
};

//////////////////////////////////////////////////////////////////////////
//车轮
class WheelShape:public PhysXPrimitive
{
public:
	WheelShape():wheel(NULL){}
	void Create(const Wheel_Desc& desc,NxActorDesc& actorDesc,NxActor* pActor);
	void SetParam(float radius);
	float GetWidth();
	float GetRadius();
	void GetWheel();
	void SetShapePtr(NxShape* p);
	bool GetWheelFlag(NxWheelFlags flag) const { return (wheel_desc.wheelFlags & flag) != 0; }
	NxVec3 GetWheelPos();
	void SetAngle(NxReal angle);
	void Tick(bool handbrake, NxReal motorTorque, NxReal brakeTorque, NxReal dt);
	NxReal GetRpm();
	NxActor* GetTouchedActor();
	NxVec3 GetGroundContactPos() const;
	void SetLateralTireForce(NxReal force);
	NxReal GetLateralTireForce();

	NxVec3 GetAABB(){return NxVec3(GetRadius()*2,GetRadius()*2,GetRadius()*2);}
public:
	typedef Wheel_Desc DescType;
protected:
	float suspension;
	NxWheelShapeDesc wheelDesc;
	NxWheelShape* wheel;
	Wheel_Desc wheel_desc;
};

//////////////////////////////////////////////////////////////////////////
//平面(地面)
class PlaneShape:public PhysXPrimitive
{
public:		
	void Create(const Plane_Desc& desc,NxActorDesc& actorDesc,NxActor* pActor);
	void SetShapePtr(NxShape* p);
	NxVec3 GetAABB(){return NxVec3(9999999,9999999,9999999);}	//尺寸近似无穷大
	typedef Plane_Desc DescType;

protected:
	NxPlaneShapeDesc planeDesc;

private:
};

//////////////////////////////////////////////////////////////////////////
// 物理物体基类
//////////////////////////////////////////////////////////////////////////

class PhysXObj
{
public:
	PhysXObj();
	virtual void CreateActor(bool isDynamic = true);
	virtual void Update();

	/// 内部初始化
	void Initial(CONST_REF(NxVec3) pos);
	void Initial();

	/// 设定一个物体的位置，受力物体在开始模拟后不可以用这个函数
	virtual void SetPos(float x,float y,float z);
	NxVec3 GetPos();
	NxMat34 GetPose();
	void SetPose(CONST_REF(NxMat34)pose);
	void DelShape(NxShape* pshape);
	int GetNShape() {return shapes.size();}
	PhysXPrimitive* GetShape(int i);
	bool FindShape(PhysXPrimitive* p);
	void RemoveShape(PhysXPrimitive* p);
	void SetScene(NxScene* s){scene = s;}

	NxScene* GetScene(){return scene;}
	NxActor* GetActor(){return actor;}

	void SetPhysRenderNode(int id, SceneNode* node){shapes[id]->SetRenderNode(node);}
	
	void SetMesh(int id,CONST_REF(string)name, CONST_REF(string)res);
	void ScaleMesh(int id, CONST_REF(Vector3)scales);

	void Show(bool val);

	void SetScriptObj(asIScriptObject* p){this->scriptObj=p;}		///<设置对应的脚本对象
	asIScriptObject* GetScriptObj(){return scriptObj;}				///<得到对应的脚本对象

	template<typename SHAPETYPE>
	SHAPETYPE* AddShape( typename SHAPETYPE::DescType& desc )
	{
		SHAPETYPE* p;
		newobj(p,SHAPETYPE);
		p->SetOwner(this);
		shapes.push_back(p);
		p->Create(desc,actorDesc,actor);
		return p;
	}	

	void AddAnyShape(boost::any& des);	
	//void AddShapeCommon(Cube_Desc& des){AddShape<CubeShape>(des);}
	//void AddShapeCommon(Sphere_Desc& des){AddShape<SphereShape>(des);}
	//void AddShapeCommon(Capsule_Desc& des){AddShape<CapsuleShape>(des);}
	//void AddShapeCommon(Wheel_Desc& des){AddShape<WheelShape>(des);}
	//void AddShapeCommon(Plane_Desc& des){AddShape<PlaneShape>(des);}
	//void AddShapeCommon(Terrain_Desc& des){AddShape<TerrainShape>(des);}

protected:
	SceneNode *renderNode;
	std::vector<PhysXPrimitive*> shapes;
	NxActor* actor;
	NxActorDesc actorDesc;
	NxScene* scene;
	asIScriptObject* scriptObj;///<对应的脚本中的对象
};

//////////////////////////////////////////////////////////////////////////
// 物理平面
class PhysPlane : public PhysXObj
{
public:
	PhysPlane(){}
	void Create(CONST_REF(NxVec3) pos);
};

//////////////////////////////////////////////////////////////////////////
// 物理地形
class PhysTerrain : public PhysXObj
{
public:
	PhysTerrain(){}
	void Create(CONST_REF(NxVec3) pos);
	void CreateFromOhm(CONST_REF(NxVec3) pos,CONST_REF(string) name ,int worldSizeX, int worldSizeZ);
};

//////////////////////////////////////////////////////////////////////////
// 立方体
class PhysBox : public PhysXObj
{
public:
	PhysBox(){}
	void Create(CONST_REF(NxVec3)pos, CONST_REF(NxVec3)size);
	///放缩，使mesh的大小与物理大小相同
	void ResertMeshSize();
};


//////////////////////////////////////////////////////////////////////////
// 球体
class PhysSphere : public PhysXObj
{
public:
	PhysSphere(){}
	void Create(CONST_REF(NxVec3)pos, float radius);
};

//////////////////////////////////////////////////////////////////////////
// 胶囊体
class PhysCapsule : public PhysXObj
{
public:
	PhysCapsule(){}
	void Create(CONST_REF(NxVec3)pos,float radius,float height);
};

_NAMESPACE_END